package com.google.code.contactserv.func.execution;
/*
*       Copyright 2007 The semap project development team.
*
*       Licensed under the Apache License, Version 2.0 (the "License");
*       you may not use this file except in compliance with the License.
*       You may obtain a copy of the License at
*
*               http://www.apache.org/licenses/LICENSE-2.0
*
*       Unless required by applicable law or agreed to in writing, software
*       distributed under the License is distributed on an "AS IS" BASIS,
*       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*       See the License for the specific language governing permissions and
*       limitations under the License.
*
*       Created by ${user} at ${date} ${time}.
*
*       ${description}.
*
*       $Id$
*/

import com.google.code.contactserv.func.model.ConsoleTest;

import java.io.*;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.StringTokenizer;

public class ClassExecutor implements Executor {
    private PipedInputStream testInput;
    private PipedOutputStream testOutput;
    private Method method;
    private Thread executionThread;
    private int exitCode = 0;

    protected ClassExecutor() throws IOException {
        PipedInputStream in = new PipedInputStream();
        PipedOutputStream out = new PipedOutputStream();

        System.setIn(in);
        System.setOut(new PrintStream(out));

        testOutput = new PipedOutputStream(in);
        testInput = new PipedInputStream(out);
    }


    protected void setExecutionMethod(Method m) {
        method = m;
    }

    public void execute(ConsoleTest test) throws IOException {
        Run run = new Run();
        run.setArguments(prepareArguments(test.getArguments()));
        run.setMethod(method);
        executionThread = new Thread(run);
        executionThread.start();
    }

    public InputStream getInputStream() {
        return testInput;
    }

    public OutputStream getOutputStream() {
        return testOutput;
    }

    public void waitFor() throws InterruptedException {
        executionThread.join();
    }

    public int exitCode() {
        return exitCode;
    }

    public String[] prepareArguments(String args) {
        List<String> out = new ArrayList<String>();
        args = args.trim();
        StringTokenizer st = new StringTokenizer(args, "\"");
        String temp;
        if (args.startsWith("\""))
            out.add(st.nextToken().trim());
        while (st.hasMoreTokens()) {
            temp = st.nextToken().trim();
            if (!temp.equals(""))
                out.addAll(Arrays.asList(temp.split(" ")));
            if (st.hasMoreTokens()) {
                out.add(st.nextToken().trim());
            }
        }

        return out.toArray(new String[]{});
    }

    private class Run implements Runnable {
        private Method m;
        private String[] args;

        public void setMethod(Method m) {
            this.m = m;
        }

        public void setArguments(String[] arg) {
            args = arg;
        }

        public void run() {
            try {
                m.invoke(null, new Object[]{args});
            } catch (InvocationTargetException e) {
                if(e.getTargetException() instanceof ExitSecurityException){
                    exitCode = ((ExitSecurityException)e.getTargetException()).getExitCode();
                    return;
                }
                e.printStackTrace();
                throw new RuntimeException(e);
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }
    }
}
